package de.tuhh.simsearch.model.persistence.usermgmt.entities;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;

/**
 * Entity implementation class for the group entity. This entity represents a user group in the database. A group has a
 * name, an administrator, members and pending users. The group name functions as a primary key in the database.
 * 
 * @author SimSearch 1
 * @see UserEntity
 */
@Entity
public class GroupEntity implements Serializable {

  private static final long serialVersionUID = 1L;

  @Id private String name;

  @ManyToOne @JoinTable(name = "USERENTITY_CREATEDGROUP") private UserEntity administrator;

  @ManyToMany(mappedBy = "joinedGroups", cascade = CascadeType.PERSIST) private Set<UserEntity> members = new HashSet<UserEntity>();

  // Set - openbook.galileocomputing.de -- 13.3.1
  @ManyToMany(mappedBy = "requestedGroups", cascade = CascadeType.PERSIST) private Set<UserEntity> pendingUsers = new HashSet<UserEntity>();

  protected GroupEntity() {

  }

  /**
   * The class constructor, sets the group name.
   * 
   * @param name
   */
  public GroupEntity(String name) {

    this.name = name;
  }

  /**
   * Gets the name of the group
   * 
   * @return the group name
   */
  public String getName() {

    return name;
  }

  /**
   * Sets the name of the group
   * 
   * @param name
   *          the group name
   */
  public void setName(String name) {

    this.name = name;
  }

  /**
   * Gets the group administrator
   * 
   * @return the user entity object of the group administrator
   */
  public UserEntity getAdministrator() {

    return administrator;
  }

  /**
   * Sets the administrator
   * 
   * @param administrator
   *          the user entity object of the group administrator
   */
  public void setAdministrator(UserEntity administrator) {

    this.administrator = administrator;
    if (!(administrator.getCreatedGroups().contains(this))) {
      administrator.addCreatedGroup(this);
    }
  }

  /**
   * Removes the administrator from the group.
   */
  public void removeAdministrator() {

    UserEntity temp = administrator;

    this.administrator = null;
    if (temp.getCreatedGroups().contains(this)) {
      temp.removeCreatedGroup(this);
    }
  }

  /**
   * Gets the set of group members. This set is unmodifiable.
   * 
   * @return the set of group members represented by their user entity objects.
   */
  public Set<UserEntity> getMembers() {

    return Collections.unmodifiableSet(members);
  }

  /**
   * Adds a member to a group
   * 
   * @param u
   *          the user entity of the new member
   */
  public void addMember(UserEntity u) {

    this.members.add(u);
    if (!(u.getJoinedGroups().contains(this))) {
      u.addJoinedGroup(this);
    }
  }

  /**
   * Removes a member from the group
   * 
   * @param u
   *          the user entity object of the member to remove
   */
  public void removeMember(UserEntity u) {

    this.members.remove(u);
    if (u.getJoinedGroups().contains(this)) {
      u.removeJoinedGroup(this);
    }
  }

  protected void setMembers(Set<UserEntity> members) {

    this.members = members;
  }

  /**
   * Gets the pending users of the group as an unmodifiable set.
   * 
   * @return the set of pending users as user entities
   */
  public Set<UserEntity> getPendingUsers() {

    return Collections.unmodifiableSet(pendingUsers);
  }

  /**
   * Adds a pending user to the group
   * 
   * @param u
   *          the entity object of the user to add as pending
   */
  public void addPendingUser(UserEntity u) {

    this.pendingUsers.add(u);
    if (!(u.getRequestedGroups().contains(this))) {
      u.addRequestedGroup(this);
    }
  }

  /**
   * Removes a pending user from the group
   * 
   * @param u
   *          the user entity of the user to remove
   */
  public void removePendingUser(UserEntity u) {

    this.pendingUsers.remove(u);
    if (u.getRequestedGroups().contains(this)) {
      u.removeRequestedGroup(this);
    }
  }

  protected void setPendingUsers(Set<UserEntity> pendingUsers) {

    this.pendingUsers = pendingUsers;
  }

}
